import { compile, Component, h } from 'vue'
import { compileString } from 'sass'

/** 编译单文件组件
 * 
 * template: 没有 script 和 style 时可以不写 <template> 直接写模板代码
 * 
 * script: 仅支持一个 script 标签且 export default 导出的视为组件
 * 
 * style: 支持 sass
 * @param {string} code - .vue 单文件组件
 * @param {object} props - 要传递给组件的属性
 * @returns {Component} - 编译的组件，可直接用于 <component :is=""></component>
 */
export function compileVue(code, props) {
  try {
    code = code.trim();
    let template;
    let script;
    let style;
    let index;
    index = code.indexOf('<script');
    if (index > 0) {
      // export default 改为 return
      // 整个脚本用闭包包起来
      script = code.substring(code.indexOf('>', index) + 1, code.indexOf('<\/script>', index));
      script = eval(`(function(){${script.replace('export default', 'return')}})`)();
    }
    index = code.indexOf('<style')
    if (index > 0) {
      style = code.substring(code.indexOf('>', index) + 1, code.indexOf('<\/style>', index));
      style = compileString(style).css;
    }
    if (code.startsWith('<template')) {
      template = code.substring(code.indexOf('>') + 1, code.lastIndexOf('<\/template>'));
    } else {
      if (!script && !style)
        template = code;
    }

    let compiled = compile(template, { mode: 'function' })
    let result = script || {};
    if (!result.mixins)
      result.mixins = [];
    result.mixins.push({
      data() {
        if (props)
          return { ...props }
        return {};
      },
      render() {
        const rendered = compiled.apply(arguments[0], arguments);
        if (style)
          return [rendered, h('style', style)];
        return rendered;
      },
    });
    return result;
  } catch(ex) {
    return ex;
  }
}